#include "WSBaseTypes.h"

WS_NS_CORE_BEGIN
//implementation of WSVertex
WSVertex::_wsVertex(GLfloat x, GLfloat y) : x(x), y(y)
{
}

WSVertex::_wsVertex(const WSVertex& other) : x(other.x), y(other.y)
{
}

WSVertex WSVertex::operator= (const WSVertex& other)
{
	x = other.x; y = other.y;
	return WSVertex(other);
}

//implementation of WSTex
WSTex::_wsTex(GLfloat u, GLfloat v) : u(u), v(v)
{}

WSTex::_wsTex(const _wsTex& other) : u(other.u), v(other.v)
{}

WSTex WSTex::operator= (const WSTex& other)
{
	u = other.u; v = other.v;
	return WSTex(other);
}

//implementation of WSColor
WSColor::_wsColor(GLuint r, GLuint g, GLuint b, GLuint a) 
	: r(r), g(g), b(b), a(a)
{}

WSColor::_wsColor(const _wsColor& other)
	: r(other.r), g(other.g), b(other.b), a(other.a)
{}

_wsColor WSColor::operator= (const _wsColor& other)
{
	r = other.r; g = other.g; b = other.b; a = other.a;
	return WSColor(other);
}

//implementation of WSPoint
WSPoint::WSPoint() : x(0), y(0)
{}

WSPoint::WSPoint(float x, float y) : x(x), y(y)
{}

WSPoint::WSPoint(const WSPoint& other) : x(other.x), y(other.y)
{}

WSPoint::WSPoint(const WSSize& size) : x(size.width), y(size.height)
{}

WSPoint& WSPoint::operator= (const WSPoint& other)
{
	SetPoint(other.x, other.y);
	return *this;
}

WSPoint& WSPoint::operator= (const WSSize& size)
{
	SetPoint(size.width, size.height);
	return *this;
}

WSPoint WSPoint::operator+ (const WSPoint& right) const
{
	return WSPoint(x + right.x, y + right.y);
}

WSPoint WSPoint::operator- (const WSPoint& right) const
{
	return WSPoint(x - right.x, y - right.y);
}

WSPoint WSPoint::operator- () const
{
	return WSPoint(-x, -y);
}

WSPoint WSPoint::operator* (float a) const
{
	return WSPoint(x * a, y * a);
}

WSPoint WSPoint::operator/ (float a) const
{
	//TODO LOG
	if (a == 0)
		a = 1;
	return WSPoint(x / a, y / a);
}

bool WSPoint::operator== (const WSPoint& right) const
{
	return (fabs(this->x - right.x) < FLT_EPSILON &&
			fabs(this->y - right.y) < FLT_EPSILON);
}

void WSPoint::SetPoint(float x, float y)
{
	this->x = x;
	this->y = y;
}

bool WSPoint::Equals(const WSPoint& target) const
{
	return *this == target;
}

bool WSPoint::FuzzyEquals(const WSPoint& target, float variance) const
{
	return (fabs(this->x - target.x) < variance &&
			fabs(this->y - target.y) < variance);
}

string WSPoint::ToString()
{
	return	"x = " + to_string(x) + ";" +
			"y = " + to_string(y);
}

//implementation of WSSize
WSSize::WSSize(void) : width(0), height(0)
{
}

WSSize::WSSize(float width, float height) : width(width), height(height)
{
}

WSSize::WSSize(const WSSize& other) : width(other.width), height(other.height)
{
}

WSSize::WSSize(const WSPoint& point) : width(point.x), height(point.y)
{
}

WSSize& WSSize::operator= (const WSSize& other)
{
    SetSize(other.width, other.height);
    return *this;
}

WSSize& WSSize::operator= (const WSPoint& point)
{
    SetSize(point.x, point.y);
    return *this;
}

WSSize WSSize::operator+(const WSSize& right) const
{
    return WSSize(this->width + right.width, this->height + right.height);
}

WSSize WSSize::operator-(const WSSize& right) const
{
    return WSSize(this->width - right.width, this->height - right.height);
}

WSSize WSSize::operator*(float a) const
{
    return WSSize(this->width * a, this->height * a);
}

WSSize WSSize::operator/(float a) const
{
	//TODO LOG
	if (a == 0)
		a = 1;

    return WSSize(width / a, height / a);
}

bool WSSize::operator== (const WSSize& right) const
{
	return (fabs(this->width  - right.width)  < FLT_EPSILON) && 
		   (fabs(this->height - right.height) < FLT_EPSILON);
}

void WSSize::SetSize(float width, float height)
{
    this->width = width;
    this->height = height;
}

bool WSSize::Equals(const WSSize& target) const
{
    return *this == target;
}

string WSSize::ToString()
{
	return	"width = " + to_string(width) + ";" +
			"height = " + to_string(height);
}

//implementation of WSRect

WSRect::WSRect() : origin(), size()
{}

WSRect::WSRect(float x, float y, float width, float height)
	: origin(x, y), size(width, height)
{}

WSRect::WSRect(const WSRect& other)
	: origin(other.origin), size(other.size)
{}

WSRect& WSRect::operator= (const WSRect& right)
{
	SetRect(right.origin.x, right.origin.y, right.size.width, right.size.height);
	return *this;
}

bool WSRect::operator== (const WSRect& right) const
{
	return origin == right.origin && size == right.size;
}

void WSRect::SetRect(float x, float y, float width, float height)
{
	origin.SetPoint(x, y);
	size.SetSize(width, height);
}

float WSRect::GetMinX() const
{
	return origin.x;
}

float WSRect::GetMidX() const
{
	return (origin.x + size.width) / 2;
}

float WSRect::GetMaxX() const
{
	return origin.x + size.width;
}

float WSRect::GetMinY() const
{
	return origin.y;
}

float WSRect::GetMidY() const
{
	return (origin.y + size.height) / 2;
}

float WSRect::GetMaxY() const
{
	return origin.y + size.height;
}

bool WSRect::Equals(const WSRect& rect) const
{
	return *this == rect;
}

bool WSRect::ContainsPoint(const WSPoint& point) const
{
	if (point.x >= GetMinX() && point.x <= GetMaxX() &&
		point.y >= GetMinY() && point.y <= GetMaxY())
		return true;
	else
		return false;
}

bool WSRect::IntersectsRect(const WSRect& rect) const
{
	float x1 = max(GetMinX(), rect.GetMinX());
	float x2 = min(GetMaxX(), rect.GetMaxX());
	float y1 = max(GetMinY(), rect.GetMinY());
	float y2 = min(GetMaxY(), rect.GetMaxY());

	if (x1 <= x2 && y1 <= y2)
		return true;
	else
		return false;
}

string WSRect::ToString()
{
	return	origin.ToString() + ";" +
			size.ToString();
}

WS_NS_CORE_END